#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
自动捕获EP加密密钥并解密data字段
"""

import frida
import sys
import time
import re
import subprocess
import os
import io

# 修复Windows编码问题
if sys.platform == 'win32':
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

PACKAGE_NAME = "com.mcdonalds.gma.cn"

# 读取JS脚本
print("📜 读取Hook脚本...")
with open('verify_rsa_key.js', 'r', encoding='utf-8') as f:
    js_code = f.read()

print("=" * 80)
print("🚀 自动捕获EP加密密钥")
print("=" * 80)
print(f"目标应用: {PACKAGE_NAME}\n")

# 捕获的数据
captured_data = {
    'aes_key': None,
    'iv': None,
    'timestamp': None
}

messages_received = []

def on_message(message, data):
    """处理Frida消息"""
    global captured_data, messages_received
    
    if message['type'] == 'send':
        payload = message.get('payload', '')
        messages_received.append(payload)
        print(payload)
        
        # 提取AES密钥
        if 'AES_set_encrypt_key' in payload or '密钥:' in payload:
            match = re.search(r'密钥:\s*([0-9a-fA-F]{64})', payload)
            if match:
                captured_data['aes_key'] = match.group(1)
                captured_data['timestamp'] = time.time()
                print(f"\n✅ 捕获到AES密钥!")
        
        # 提取IV
        if 'IV:' in payload or 'iv:' in payload.lower():
            match = re.search(r'IV:\s*([0-9a-fA-F]{32})', payload, re.IGNORECASE)
            if match:
                captured_data['iv'] = match.group(1)
                print(f"✅ 捕获到IV!")
        
        # 从RSA加密的明文中提取（前32字节是AES密钥，后16字节是IV）
        if 'RSA_public_encrypt' in payload and '📄 明文' in payload:
            lines = payload.split('\n')
            hex_data = []
            for line in lines:
                if re.match(r'^\d{4}:', line):
                    # 提取十六进制数据
                    hex_line = line.split(':', 1)[1].split('#')[0].strip()
                    hex_bytes = hex_line.replace(' ', '')
                    hex_data.append(hex_bytes)
            
            if hex_data:
                full_hex = ''.join(hex_data)
                if len(full_hex) >= 96:  # 48字节 = 96个十六进制字符
                    captured_data['aes_key'] = full_hex[:64]  # 前32字节
                    captured_data['iv'] = full_hex[64:96]      # 后16字节
                    captured_data['timestamp'] = time.time()
                    print(f"\n✅ 从RSA明文提取:")
                    print(f"   AES密钥: {captured_data['aes_key']}")
                    print(f"   IV: {captured_data['iv']}")
        
    elif message['type'] == 'error':
        print(f"❌ 错误: {message.get('stack', message)}")

try:
    # 连接设备
    print("📱 连接设备...")
    device = frida.get_usb_device()
    print(f"✓ 已连接: {device}\n")
    
    # 启动应用
    print(f"🚀 启动应用 {PACKAGE_NAME}...")
    try:
        # 先杀掉可能存在的进程
        try:
            device.kill(PACKAGE_NAME)
            time.sleep(1)
        except:
            pass
        
        pid = device.spawn([PACKAGE_NAME])
        session = device.attach(pid)
        print(f"✓ 应用已启动 (PID: {pid})")
    except Exception as e:
        print(f"⚠️  启动失败，尝试附加到现有进程...")
        session = device.attach(PACKAGE_NAME)
        print(f"✓ 已附加到应用")
    
    # 加载脚本
    print("\n📜 加载Hook脚本...")
    script = session.create_script(js_code)
    script.on('message', on_message)
    script.load()
    print("✓ Hook脚本已加载\n")
    
    # 恢复进程
    try:
        device.resume(pid)
    except:
        pass
    
    print("=" * 80)
    print("✅ Hook已激活！等待SDK调用...")
    print("=" * 80)
    print("\n提示: 现在需要在应用中触发数美SDK")
    print("      (登录、注册、提交表单等操作)\n")
    print("      等待60秒...\n")
    
    # 等待60秒捕获数据
    start_time = time.time()
    timeout = 60
    
    while time.time() - start_time < timeout:
        time.sleep(2)
        
        # 检查是否捕获到密钥
        if captured_data['aes_key'] and captured_data['iv']:
            print("\n" + "=" * 80)
            print("🎉 成功捕获密钥！")
            print("=" * 80)
            print(f"AES密钥: {captured_data['aes_key']}")
            print(f"IV: {captured_data['iv']}")
            print("=" * 80)
            
            # 保存到文件
            with open('captured_keys.txt', 'w', encoding='utf-8') as f:
                f.write(f"AES密钥: {captured_data['aes_key']}\n")
                f.write(f"IV: {captured_data['iv']}\n")
                f.write(f"\n捕获时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(captured_data['timestamp']))}\n")
            
            print("\n✅ 密钥已保存到 captured_keys.txt\n")
            
            # 现在尝试解密
            print("=" * 80)
            print("🔓 开始解密data字段")
            print("=" * 80)
            
            # 检查是否有最近的data可以解密
            # 这里我们需要从某处获取data字段，让我先保存密钥
            print("\n下一步:")
            print("1. 从API响应中复制 'data' 字段")
            print("2. 运行: java DecryptWithCapturedKey")
            print("3. 粘贴密钥和data进行解密\n")
            
            break
        
        # 显示进度
        elapsed = int(time.time() - start_time)
        remaining = timeout - elapsed
        if elapsed % 10 == 0:
            print(f"⏱️  已等待 {elapsed}秒，还剩 {remaining}秒...")
    
    if not (captured_data['aes_key'] and captured_data['iv']):
        print("\n⚠️  超时: 未捕获到完整的密钥数据")
        print("\n可能的原因:")
        print("1. 应用还未触发数美SDK")
        print("2. 需要在应用中执行特定操作（登录、注册等）")
        print("3. Hook点可能需要调整")
        
        if messages_received:
            print(f"\n已接收到 {len(messages_received)} 条消息")
            print("请查看上面的输出，看是否有Hook到相关函数")
    
    session.detach()
    
except KeyboardInterrupt:
    print("\n\n⚠️  用户中断")
except Exception as e:
    print(f"\n❌ 错误: {e}")
    import traceback
    traceback.print_exc()
    sys.exit(1)

print("\n脚本结束")

